﻿Public Class DungeonDeckManager

    Public Property MainDeck As DeckObj
    Public Property BackUpDeck As DeckObj
    Public Property UsedObjectiveRooms As List(Of DungeonTheme.eObjectiveRoom)

    Public Sub CreateDungeonDecks(ByVal objectiveRoomId As DungeonTheme.eObjectiveRoom)

        UsedObjectiveRooms = New List(Of DungeonTheme.eObjectiveRoom) From {objectiveRoomId}
        MainDeck = New DeckObj
        BackUpDeck = New DeckObj

        '18 pieces in the full deck (not including any objective rooms)
        Dim allPieces As New List(Of DungeonPieceObj) From {New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New TJunctionObj,
                                                            New TJunctionObj,
                                                            New TJunctionObj,
                                                            New CornerObj}


        Dim objectiveRoom As New ObjectiveRoomObj

        'get a number 1-7 for our objective room's place in line
        Dim objectiveRoomIndex As Short = AppConstants.DxRoll(7)

        While objectiveRoomIndex > MainDeck.Count + 1
            Dim allPieceIndex As Short = AppConstants.DxRoll(allPieces.Count) - 1
            MainDeck.AddRoomToTopOfDeck(allPieces(allPieceIndex))
            allPieces.RemoveAt(allPieceIndex)
        End While

        MainDeck.AddRoomToTopOfDeck(objectiveRoom)

        While MainDeck.Count < 14
            Dim allPieceIndex As Short = AppConstants.DxRoll(allPieces.Count) - 1
            MainDeck.AddRoomToTopOfDeck(allPieces(allPieceIndex))
            allPieces.RemoveAt(allPieceIndex)
        End While

        While allPieces.Count > 0
            Dim allPieceIndex As Short = AppConstants.DxRoll(allPieces.Count) - 1
            BackUpDeck.AddRoomToTopOfDeck(allPieces(allPieceIndex))
            allPieces.RemoveAt(allPieceIndex)
        End While

    End Sub

    ''' <summary>
    ''' in case we run out
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub FillBackUpDeck()

        Dim allPieces As New List(Of DungeonPieceObj) From {New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New DungeonRoomObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New CorridorObj,
                                                            New TJunctionObj,
                                                            New TJunctionObj,
                                                            New TJunctionObj,
                                                            New CornerObj}

        While allPieces.Count > 0
            Dim allPieceIndex As Short = AppConstants.DxRoll(allPieces.Count) - 1
            BackUpDeck.AddRoomToTopOfDeck(allPieces(allPieceIndex))
            allPieces.RemoveAt(allPieceIndex)
        End While

    End Sub

    Public Class DeckObj

        Private _topNode As DeckNodeObj

        Public Sub ClearDeck()
            While Count > 0
                PopTopRoom()
            End While
        End Sub

        Public Sub AddRoomToTopOfDeck(ByVal room As DungeonPieceObj)
            Dim newNode As New DeckNodeObj(room)
            Dim lastTopNode As DeckNodeObj = _topNode

            _topNode = newNode

            If lastTopNode IsNot Nothing Then
                lastTopNode.NextNodeUp = _topNode
                _topNode.PreviousNodeDown = lastTopNode
            End If

        End Sub

        Public Function PopTopRoom() As DungeonPieceObj

            Dim top As DeckNodeObj = _topNode

            If _topNode.PreviousNodeDown IsNot Nothing Then
                _topNode = top.PreviousNodeDown
                _topNode.NextNodeUp = Nothing
            End If

            Return top.RoomAtNode

        End Function

        Public Function PopBottomRoom() As DungeonPieceObj

            Dim bottomNode As DeckNodeObj = GetBottomNode()

            If bottomNode IsNot _topNode Then
                'detach bottom node
                Dim newBottomNode As DeckNodeObj = bottomNode.NextNodeUp()
                newBottomNode.PreviousNodeDown = Nothing
            End If

            Return bottomNode.RoomAtNode()

        End Function

        Public Function PopRoomAtIndex(ByVal index As Integer) As DungeonPieceObj

            Dim nodeAtIndex As DeckNodeObj = GetNodeAtIndex(index)

            Dim nextNodeUp As DeckNodeObj = Nothing
            Dim previousNodeDown As DeckNodeObj = Nothing

            If nodeAtIndex.NextNodeUp IsNot Nothing Then

                nextNodeUp = nodeAtIndex.NextNodeUp()
                nextNodeUp.PreviousNodeDown = Nothing

            ElseIf nodeAtIndex.PreviousNodeDown IsNot Nothing Then

                _topNode = nodeAtIndex.PreviousNodeDown

            Else

                _topNode = Nothing

            End If

            If nodeAtIndex.PreviousNodeDown IsNot Nothing Then
                previousNodeDown = nodeAtIndex.PreviousNodeDown()
                previousNodeDown.NextNodeUp = Nothing
            End If

            If nextNodeUp IsNot Nothing AndAlso previousNodeDown IsNot Nothing Then
                previousNodeDown.NextNodeUp = nextNodeUp
                nextNodeUp.PreviousNodeDown = previousNodeDown
            End If

            Return nodeAtIndex.RoomAtNode

        End Function

        Public Function PeekAtTopRoom() As DungeonPieceObj
            Return If(_topNode IsNot Nothing, _topNode.RoomAtNode, Nothing)
        End Function

        Public Function PeekAtBottomRoom() As DungeonPieceObj
            Dim currentNode As DeckNodeObj = GetBottomNode()
            Return currentNode.RoomAtNode()
        End Function

        Public Function PeekAtRoomAtIndex(ByVal index As Integer) As DungeonPieceObj
            Dim currentNode As DeckNodeObj = GetNodeAtIndex(index)
            Return currentNode.RoomAtNode()
        End Function


        Private Function GetBottomNode() As DeckNodeObj
            Dim currentNode As DeckNodeObj = _topNode

            While currentNode.PreviousNodeDown IsNot Nothing
                currentNode = currentNode.PreviousNodeDown
            End While

            Return currentNode

        End Function

        Private Function GetNodeAtIndex(ByVal targetIndex As Integer) As DeckNodeObj

            Dim currentNode As DeckNodeObj = _topNode
            Dim currentIndex As Integer = 0

            While currentNode.PreviousNodeDown IsNot Nothing AndAlso currentIndex < targetIndex
                currentNode = currentNode.PreviousNodeDown
                currentIndex += 1
            End While

            If currentIndex <> targetIndex Then Throw New IndexOutOfRangeException("target index out of range in deck class")

            Return currentNode

        End Function

        Public ReadOnly Property Count As Integer
            Get
                Dim currentNode As DeckNodeObj = _topNode
                Dim currentCount As Integer = If(currentNode IsNot Nothing, 1, 0)

                If currentNode IsNot Nothing Then
                    While currentNode.PreviousNodeDown IsNot Nothing
                        currentNode = currentNode.PreviousNodeDown
                        currentCount += 1
                    End While
                End If

                Return currentCount
            End Get
        End Property

    End Class

    Public Class DeckNodeObj

        Public Property RoomAtNode As DungeonPieceObj
        Public Property NextNodeUp As DeckNodeObj
        Public Property PreviousNodeDown As DeckNodeObj

        Public Sub New(ByVal dungeonPiece As DungeonPieceObj)
            RoomAtNode = dungeonPiece
        End Sub

    End Class

End Class
